home *** CD-ROM | disk | FTP | other *** search
/ Die Speccy' 97 / Die Speccy' 97.iso / amiga_system / the_aminet / util / boot / avwm.lzh / avwm-0.4 / avwm.c < prev    next >
C/C++ Source or Header  |  1994-08-08  |  19KB  |  773 lines

  1. /*
  2.     avwm 0.4 / Amiga Virtual Workbench Manager
  3.     5/2/93 Bernhard Fastenrath
  4.     Public Domain
  5. */
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <signal.h>
  11. #include <dos.h>
  12. #include <exec/types.h>
  13. #include <devices/timer.h>
  14. #include <graphics/rastport.h>
  15. #include <intuition/intuitionbase.h>
  16. #include <proto/dos.h>
  17. #include <proto/exec.h>
  18. #include <proto/graphics.h>
  19. #include <proto/intuition.h>
  20.  
  21. #include "callbacks.h"
  22. #include "avwm.h"
  23. #include "wbwm.h"
  24.  
  25. const char        *Version = VERSION;
  26.  
  27. struct IntuitionBase    *IntuitionBase = NULL;
  28. struct timerequest    *TimerIO = NULL;
  29. struct MsgPort        *TimerPort = NULL;
  30. struct Window        *Win = NULL,
  31.             *LastActiveWindow = NULL;
  32. struct RastPort        *Rp;
  33. short            Screenwidth, Screenheight,
  34.             VisWidth, VisHeight;
  35. struct List        VWinA[2];
  36. int            Options = OPT_NO_SETF | OPT_MOVE_SCREEN,
  37.             VWIndex = 0, Dx, Dy,
  38.             Action = ACT_NONE, Area = 0,
  39.             Seconds = 2, MSeconds = 0;
  40.             Offset = 11;
  41. ULONG            WMSigBit = -1, WMSig;
  42. struct vWindow        *Cvw = NULL;
  43. char            *PubScreenName = "Workbench";
  44.  
  45. int
  46. main (int argc, char *argv[])
  47. {
  48.   struct Screen *Lock;
  49.   struct NewWindow NewWin;
  50.   int argn = 1;
  51.   char optc;
  52.  
  53.   while (argn < argc)
  54.     if (argopt (argc, argv, "OcS", &argn, &optc))
  55.       switch (optc) {
  56.     case 'O':
  57.       Offset = atoi (argv[argn-1] + (argv[argn-1][0] == '-' ? 2 : 0));
  58.       break;
  59.         case 'h':
  60.       printf ("Amiga Virtual Workbench Manager %d.%d\n", VER_NUM, REV_NUM);
  61.       printf ("Options: -t don't open timer device.\n");
  62.       printf ("         -c <n> check windows every n seconds (default: 2s).\n");
  63.       printf ("         -s use SetFunction () (by default disabled now).\n");
  64.       printf ("         -m use MoveWindow (expects double v. screen size) instead of\n");
  65.       printf ("            MoveScreen (expects triple h. and double v. screen size).\n");
  66.       printf ("         -S Name of public screen (default: Workbench).\n");
  67.       exit (0);
  68.     case 'c':
  69.           Seconds = atoi (argv[argn-1] + (argv[argn-1][0] == '-' ? 2 : 0));
  70.       if (Seconds == 0) MSeconds = 250;
  71.       break;
  72.         case 't':
  73.       Options |= OPT_NO_TIMER;
  74.       break;
  75.         case 's':
  76.       Options &= ~OPT_NO_SETF;
  77.       break;
  78.     case 'm':
  79.       Options &= ~OPT_MOVE_SCREEN;
  80.       break;
  81.     case 'S':
  82.           PubScreenName = argv[argn-1] + (argv[argn-1][0] == '-' ? 2 : 0);
  83.       break;
  84.         default:
  85.       printf ("Invalid Option: \"-%c\" (try '%s -h')\n", optc, argv[0]);
  86.       exit (20);
  87.       }
  88.     else
  89.       argn++;
  90.  
  91.   InitListHeader ((struct MinList *) &VWinA[0]);
  92.   InitListHeader ((struct MinList *) &VWinA[1]);
  93.  
  94.   if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 37L))) {
  95.     printf ("%s: Can't open intuition library 37.x.\n", Version);
  96.     exit_avwm (1);
  97.   }
  98.   if ((Lock = LockPubScreen (PubScreenName)) == NULL) {
  99.     printf ("%s: Can't lock public screen '%s'.\n", Version, PubScreenName);
  100.     exit_avwm (1);
  101.   }
  102.   Screenwidth = Lock -> Width;
  103.   Screenheight = Lock -> Height;
  104.  
  105.   if (Options & OPT_MOVE_SCREEN) {
  106.     VisWidth = Screenwidth / 3;
  107.     VisHeight = Screenheight / 2;
  108.   }
  109.   else {
  110.     VisWidth = Screenwidth;
  111.     VisHeight = Screenheight / 2;
  112.   }
  113.   NewWin.LeftEdge = VisWidth - AVWM_WIDTH;
  114.   NewWin.TopEdge = 12;
  115.   NewWin.Width = AVWM_WIDTH;
  116.   NewWin.Height = AVWM_HEIGHT;
  117.   NewWin.DetailPen = 0;
  118.   NewWin.BlockPen = 1;
  119.   NewWin.Title = "Virtual Desktop";
  120.   NewWin.Flags = WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SMART_REFRESH |
  121.          GIMMEZEROZERO | ACTIVATE | RMBTRAP | REPORTMOUSE;
  122.   NewWin.IDCMPFlags = MOUSEBUTTONS | CLOSEWINDOW | REFRESHWINDOW | MOUSEMOVE;
  123.   NewWin.Type = PUBLICSCREEN;
  124.   NewWin.FirstGadget = NULL;
  125.   NewWin.CheckMark = NULL;
  126.   NewWin.Screen = Lock;
  127.   NewWin.BitMap = NULL;
  128.   NewWin.MinWidth = 0;
  129.   NewWin.MinHeight = 0;
  130.   NewWin.MaxWidth = 0;
  131.   NewWin.MaxHeight = 0;
  132.  
  133.   if (!(Win = OpenWindow (&NewWin))) {
  134.     UnlockPubScreen (NULL, Lock);
  135.     printf ("%s: Can't open window.\n", Version);
  136.     exit_avwm (20);
  137.   }
  138.   UnlockPubScreen (NULL, Lock);
  139.   Rp = Win -> RPort;
  140.  
  141.   AddCallback (Win, close_window, CLOSEWINDOW);
  142.   AddCallback (Win, mouse_event, MOUSEBUTTONS);
  143.   AddCallback (Win, refresh_window, REFRESHWINDOW);
  144.   AddCallback (Win, mouse_move, MOUSEMOVE);
  145.  
  146.   if ((Options & OPT_NO_TIMER) == 0)
  147.   {
  148.     init_timer ();
  149.     AddPortCallback (TimerPort, (callback) timer_event, 0);
  150.   }
  151.  
  152.   if ((Options & OPT_NO_SETF) == 0)
  153.   {
  154.     if ((WMSigBit = AllocSignal (-1)) == -1)
  155.     {
  156.       printf ("%s: Can't allocate Signal.\n", Version);
  157.       exit_avwm (20);
  158.     }
  159.     start_window_monitor ();
  160.     WMSig = 1L << WMSigBit;
  161.     SetSignalCallback (WMSig, (callback) workbench_monitor_event);
  162.   }
  163.   refresh_graphic ();
  164.  
  165.   AppMainLoop ();
  166.  
  167.   exit_avwm (0);
  168. }
  169.  
  170. void
  171. exit_avwm (int code)
  172. {
  173.   struct Node *node;
  174.  
  175.   stop_window_monitor ();
  176.   while (node = RemTail (&VWinA[0]))
  177.     free (node);
  178.   while (node = RemTail (&VWinA[1]))
  179.     free (node);
  180.   if (WMSigBit != -1) FreeSignal (WMSigBit);
  181.   if (Win) CloseWindow (Win);
  182.   if ((Options & OPT_NO_SETF) == 0) Delay (100);
  183.   if (TimerIO) {
  184.     AbortIO ((struct IORequest *) TimerIO);
  185.     WaitIO ((struct IORequest *) TimerIO);
  186.     CloseDevice ((struct IORequest *) TimerIO);
  187.     DeleteExtIO ((struct IORequest *) TimerIO, sizeof (struct timerequest));
  188.   }
  189.   if (TimerPort) DeletePort (TimerPort);
  190.   RemoveAllCallbacks ();
  191.   if (IntuitionBase) CloseLibrary ((struct Library *) IntuitionBase);
  192.   exit (code);
  193. }
  194.  
  195. void
  196. init_timer ()
  197. {
  198.   int err;
  199.  
  200.   if (!(TimerPort = CreatePort (0, 0)))
  201.   {
  202.     printf ("%s: Can't create message port.\n", Version);
  203.     exit_avwm (1);
  204.   }
  205.   if (!(TimerIO = (struct timerequest *) CreateExtIO (TimerPort, sizeof (struct timerequest))))
  206.   {
  207.     printf ("%s: Out of memory.\n", Version);
  208.     exit_avwm (1);
  209.   }
  210.   if (err = OpenDevice (TIMERNAME, UNIT_VBLANK, (struct IORequest *) TimerIO, 0))
  211.   {
  212.     printf ("%s: Can't open timer.device (code %d).\n", Version, err);
  213.     exit_avwm (1);
  214.   }
  215.   TimerIO -> tr_time.tv_secs = Seconds;
  216.   TimerIO -> tr_time.tv_micro = MSeconds;
  217.   TimerIO -> tr_node.io_Command = TR_ADDREQUEST;
  218.   SendIO ((struct IORequest *) TimerIO);
  219. }
  220.  
  221. struct Window *
  222. assert_window (struct Window *search)
  223. {
  224.   struct Window *window;
  225.  
  226.   for (window = Win -> WScreen -> FirstWindow; window; window = window -> NextWindow)
  227.     if (search == window) return window;
  228.  
  229.   return NULL;
  230. }
  231.  
  232. void
  233. draw_box (short color, short x1, short y1, short x2, short y2, struct RastPort *rp)
  234. {
  235.   SetAPen (rp, GREY);
  236.  
  237.   RectFill (rp, x1, y1, x2, y2);
  238.  
  239.   SetAPen (rp, color);
  240.  
  241.   Move (rp, x1, y1);
  242.   Draw (rp, x2, y1);
  243.   Draw (rp, x2, y2);
  244.   Draw (rp, x1, y2);
  245.   Draw (rp, x1, y1);
  246. }
  247.  
  248. void
  249. draw_frame (short color, short x1, short y1, short x2, short y2, struct RastPort *rp)
  250. {
  251.   SetAPen (rp, color);
  252.  
  253.   Move (rp, x1, y1);
  254.   Draw (rp, x2, y1);
  255.   Draw (rp, x2, y2);
  256.   Draw (rp, x1, y2);
  257.   Draw (rp, x1, y1);
  258. }
  259.  
  260. void
  261. draw_vwindow (int color, struct vWindow *vw)
  262. {
  263.   int x, y;
  264.  
  265.   x = vw -> sx + AREA_X (vw -> area) * SUB_WIDTH;
  266.   y = vw -> sy + AREA_Y (vw -> area) * SUB_HEIGHT;
  267.  
  268.   draw_frame (color, x, y, x + vw -> sw, y + vw -> sh, Rp);
  269. }
  270.  
  271. void
  272. redraw_graphic ()
  273. {
  274.   struct vWindow *vw;
  275.   struct List *vwl;
  276.   short color;
  277.   int x, y;
  278.  
  279.   vwl = &VWinA[VWIndex];
  280.  
  281.   SetDrMd (Rp, JAM2);
  282.   SetAPen (Rp, GREY);
  283.  
  284.   RectFill (Rp, 0, 0, AVWM_WIDTH, AVWM_HEIGHT);
  285.  
  286.   SetAPen (Rp, BLACK);
  287.  
  288.   Move (Rp, 0, SUB_HEIGHT);    Draw (Rp, SUB_WIDTH * 3, SUB_HEIGHT);
  289.   Move (Rp, SUB_WIDTH, 0);     Draw (Rp, SUB_WIDTH, SUB_HEIGHT * 2);
  290.   Move (Rp, SUB_WIDTH * 2, 0); Draw (Rp, SUB_WIDTH * 2, SUB_HEIGHT * 2);
  291.  
  292.   for (vw = (struct vWindow *) vwl -> lh_TailPred;
  293.        vw -> node.ln_Pred; vw = (struct vWindow *) vw -> node.ln_Pred)
  294.   {
  295.     if (IntuitionBase -> ActiveWindow == vw -> window)
  296.        color = BLUE;
  297.     else
  298.        color = BLACK;
  299.  
  300.     x = vw -> sx + AREA_X (vw -> area) * SUB_WIDTH;
  301.     y = vw -> sy + AREA_Y (vw -> area) * SUB_HEIGHT;
  302.  
  303.     draw_box (color, x, y, x + vw -> sw, y + vw -> sh, Rp);
  304.   }
  305. }
  306.  
  307. void
  308. refresh_graphic ()
  309. {
  310.   struct Window *window;
  311.   struct vWindow *vw;
  312.   short change = 0;
  313.   BYTE pos;
  314.   struct List *vwl, *vwl2;
  315.   struct Layer *layer;
  316.   int area;
  317.  
  318.   Forbid ();
  319.  
  320.   if (IntuitionBase -> FirstScreen != Win -> WScreen
  321.       && IntuitionBase -> ActiveScreen != Win -> WScreen)
  322.   {
  323.     Permit ();
  324.     return;    /* Screen not in use, event ignored */
  325.   }
  326.   vwl = &VWinA[VWIndex];
  327.   VWIndex = 1 - VWIndex;
  328.   vwl2 = &VWinA[VWIndex];
  329.  
  330.   if (LastActiveWindow != IntuitionBase -> ActiveWindow)
  331.   {
  332.     LastActiveWindow = IntuitionBase -> ActiveWindow;
  333.     change = 1;
  334.   }
  335.  
  336.   /* Set the change status of all windows to "unknown" */
  337.   for (vw = (struct vWindow *) vwl -> lh_Head;
  338.        vw -> node.ln_Succ; vw = (struct vWindow *) vw -> node.ln_Succ)
  339.   {
  340.     vw -> changed = -1;
  341.   }
  342.  
  343.   /* Find the front layer */
  344.   for (layer = Win -> WScreen -> FirstWindow -> WLayer;
  345.        layer -> front; layer = layer -> front);
  346.  
  347.   /* Sort the virtual window list like the layers of the screen
  348.      and check if size, position or priority of any window changed
  349.   */
  350.   for (pos = HIGH_PRI; layer -> back; pos--, layer = layer -> back)
  351.   {
  352.     if (!(window = layer -> Window)) continue;
  353.  
  354.     for (vw = (struct vWindow *) vwl -> lh_Head;
  355.      vw -> node.ln_Succ; vw = (struct vWindow *) vw -> node.ln_Succ)
  356.     {
  357.       if (vw -> window == window)
  358.       {
  359.         if (vw -> changed != -1) break;
  360.  
  361.     vw -> changed = 0;    /* Window has moved? */
  362.  
  363.     if (vw -> ox != window -> LeftEdge)
  364.       { vw -> ox = window -> LeftEdge; change = vw -> changed = 1; }
  365.     if (vw -> oy != window -> TopEdge)  
  366.       { vw -> oy = window -> TopEdge;  change = vw -> changed = 1; }
  367.     if (vw -> ow != window -> Width)    
  368.       { vw -> ow = window -> Width;    change = vw -> changed = 1; }
  369.     if (vw -> oh != window -> Height)   
  370.       { vw -> oh = window -> Height;   change = vw -> changed = 1; }
  371.  
  372.     if (vw -> changed)
  373.     {
  374.       /* Window has moved into another area? */
  375.       area = AREA (window -> LeftEdge, window -> TopEdge);
  376.  
  377.       /* Don't change the area if MoveWindow is used
  378.          and the window is invisible
  379.          because it will always be found in the lower
  380.          "invisible" part of the screen
  381.       */
  382.           if (Options & OPT_MOVE_SCREEN)
  383.         vw -> area = area;
  384.       else if (area == 0)
  385.         vw -> area = Area;
  386.  
  387. #ifdef DEBUG
  388.       printf ("Window %d moved to %d,%d in area %d.\n", vw -> window, vw -> ox, vw -> oy, area);
  389. #endif
  390.     }
  391.  
  392.     if (vw -> node.ln_Pri != pos) /* Window order has changed */
  393.     {
  394. #ifdef DEBUG
  395.       printf ("Window order has changed. (area %d) [was: %d, is: %d]\n", vw->area, vw->node.ln_Pri, pos);
  396. #endif
  397.       vw -> node.ln_Pri = pos;
  398.       change = 1;
  399.     }
  400.     break;
  401.       }
  402.     }
  403.  
  404.     if (!vw -> node.ln_Succ) /* New window has been opened */
  405.     {
  406.       if (!(vw = Malloc (struct vWindow))) {
  407.     Permit ();
  408.     printf ("%s: Memory low!.\n", Version);
  409.     exit_avwm (1);
  410.       }
  411.       vw -> area = AREA (window -> LeftEdge, window -> TopEdge);
  412.  
  413.       /* Set the area to the area currently displayed in area 0 */
  414.       if (!(Options & OPT_MOVE_SCREEN) && vw -> area == 0)
  415.         vw -> area = Area;
  416.  
  417. #ifdef DEBUG
  418.       printf ("Adding window to area %d.\n", vw -> area);
  419. #endif
  420.       vw -> changed = 2;
  421.       vw -> window = window;
  422.       vw -> node.ln_Pri = pos;
  423.       vw -> ox = window -> LeftEdge;
  424.       vw -> oy = window -> TopEdge;
  425.       vw -> ow = window -> Width;
  426.       vw -> oh = window -> Height;
  427.  
  428.       AddHead (vwl, (struct Node *) vw);
  429.  
  430.       change = 1;
  431.     }
  432.   } 
  433.   Permit ();
  434.  
  435.   while (vw = (struct vWindow *) RemTail (vwl))
  436.   {
  437.     if (vw -> changed == -1) { /* Window has been closed */
  438.       free (vw);
  439.       change = 1;
  440. #ifdef DEBUG
  441.       printf ("Window removed.\n");
  442. #endif
  443.     }
  444.     else /* If the window order is unchanged this is just an AddHead() */
  445.       Enqueue (vwl2, (struct Node *) vw);
  446.   }
  447.  
  448.   if (change)    /* Don't draw if nothing has happened */
  449.   {
  450.     if (Options & OPT_MOVE_SCREEN)
  451.       for (vw = (struct vWindow *) vwl2 -> lh_TailPred;
  452.        vw -> node.ln_Pred; vw = (struct vWindow *) vw -> node.ln_Pred)
  453.       {
  454.         vw -> sx = (vw -> ox % VisWidth)  * SUB_WIDTH  / VisWidth;
  455.         vw -> sy = (vw -> oy % VisHeight) * SUB_HEIGHT / VisHeight;
  456.         vw -> sw = vw -> ow * SUB_WIDTH  / VisWidth;
  457.         vw -> sh = vw -> oh * SUB_HEIGHT / VisHeight;
  458.       }
  459.     else
  460.       for (vw = (struct vWindow *) vwl2 -> lh_TailPred;
  461.        vw -> node.ln_Pred; vw = (struct vWindow *) vw -> node.ln_Pred)
  462.       {
  463.         /* ignore window's position (but not size)
  464.            if it is invisible
  465.         */
  466.     if (vw -> area == Area || vw -> changed == 2)
  467.     {
  468.           vw -> sx = (vw -> ox % VisWidth)  * SUB_WIDTH  / VisWidth;
  469.           vw -> sy = (vw -> oy % VisHeight) * SUB_HEIGHT / VisHeight;
  470.         }
  471.         vw -> sw = vw -> ow * SUB_WIDTH  / VisWidth;
  472.         vw -> sh = vw -> oh * SUB_HEIGHT / VisHeight;
  473.       }
  474.     redraw_graphic ();
  475.   }
  476. }
  477.  
  478. struct vWindow *
  479. find_window (int x, int y)
  480. {
  481.   struct vWindow *vw;
  482.   struct List *vwl;
  483.   int area;
  484.  
  485.   vwl = &VWinA[VWIndex];
  486.  
  487.   area = vAREA (x, y); x %= SUB_WIDTH; y %= SUB_HEIGHT;
  488.  
  489.   for (vw = (struct vWindow *) vwl -> lh_Head;
  490.        vw -> node.ln_Succ; vw = (struct vWindow *) vw -> node.ln_Succ)
  491.   {
  492.     if (x > vw->sx && y > vw->sy && x < vw->sw + vw->sx && y < vw->sh + vw->sy
  493.     && area == vw -> area)
  494.       return vw;
  495.   }
  496.   return NULL;
  497. }
  498.  
  499. int
  500. close_window (struct IntuiMessage *msg, struct Callback *cb)
  501. {
  502.   exit_avwm (0);
  503.   return 0;
  504. }
  505.  
  506. int
  507. refresh_window (struct IntuiMessage *msg, struct Callback *cb)
  508. {
  509.   return 0;
  510. }
  511.  
  512. int
  513. timer_event (struct timerequest *msg, struct Callback *cb)
  514. {
  515.   TimerIO -> tr_time.tv_secs = Seconds;
  516.   TimerIO -> tr_time.tv_micro = MSeconds;
  517.   TimerIO -> tr_node.io_Command = TR_ADDREQUEST;
  518.   SendIO ((struct IORequest *) TimerIO);
  519.  
  520.   if (!Action) refresh_graphic ();
  521.   return 0;
  522. }
  523.  
  524. void
  525. workbench_monitor_event (int signals)
  526. {
  527. #ifdef xDEBUG
  528.   printf ("Monitor Event (signal: %d).\n", signals);
  529. #endif
  530.   if (!Action) refresh_graphic ();
  531. #ifdef xDEBUG
  532.   else printf ("Monitor Event ignored.\n");
  533. #endif  
  534. }
  535.  
  536. int
  537. mouse_move (struct IntuiMessage *msg, struct Callback *cb)
  538. {
  539.   if (Action == ACT_NONE) return 0;
  540.  
  541.   if (Action == ACT_MOVE_WIN)
  542.   {
  543.     draw_vwindow (WHITE, Cvw);
  544.     Cvw -> sx += msg -> MouseX - Dx;
  545.     Cvw -> sy += msg -> MouseY - Dy;
  546.     Dx = msg -> MouseX;
  547.     Dy = msg -> MouseY;
  548.     draw_vwindow (WHITE, Cvw);
  549.   }
  550.   return 0;
  551. }
  552.  
  553. static void
  554. change_area (int x, int y)
  555. {
  556.   struct vWindow *vw;
  557.   WORD dx, dy;
  558.   short oldarea;
  559.  
  560.   oldarea = Area;
  561.   Area = vAREA (x, y);
  562.  
  563.   if (oldarea == Area)
  564.     return;
  565.  
  566. #ifdef xDEBUG
  567.   printf ("Visible area was %d, now %d.\n", oldarea, Area);
  568. #endif
  569.  
  570.   if (Options & OPT_MOVE_SCREEN)
  571.   {
  572.     dx = VisWidth  * AREA_X (Area) + Win -> WScreen -> LeftEdge;
  573.     dy = VisHeight * AREA_Y (Area) + Win -> WScreen -> TopEdge;
  574.  
  575.     MoveScreen (Win -> WScreen, -dx, -dy);
  576.  
  577.     MoveWindow (Win, dx, dy); 
  578.   }
  579.   else
  580.   {
  581.     for (vw = (struct vWindow *) VWinA[VWIndex].lh_Head;
  582.      vw -> node.ln_Succ; vw = (struct vWindow *) vw -> node.ln_Succ)
  583.     {
  584.       if (vw -> window == Win) /* The awvm window always stays */
  585.       {
  586.         vw -> area = Area;
  587.       }
  588.       else if (vw -> area == oldarea)
  589.       {
  590.         Forbid ();
  591.  
  592.     if (assert_window (vw -> window))    /* Move it away */
  593.         {
  594.       ChangeWindowBox (vw -> window,
  595.         0, VisHeight,
  596.         vw -> window -> Width,
  597.         vw -> window -> Height);
  598.         }
  599.  
  600.         Permit ();
  601.       }
  602. #if 0 /* Remove, then add windows -- this looks better and is probably faster */
  603.       else if (vw -> area == Area)
  604. #else
  605.     }
  606.     for (vw = (struct vWindow *) VWinA[VWIndex].lh_Head;
  607.      vw -> node.ln_Succ; vw = (struct vWindow *) vw -> node.ln_Succ)
  608.     {
  609.       if (vw -> area == Area && vw -> window != Win)
  610. #endif
  611.       {
  612.         Forbid ();
  613.  
  614.         if (assert_window (vw -> window))    /* Make it visible */
  615.         {
  616.       ChangeWindowBox (vw -> window,
  617.         vw -> sx * VisWidth  / SUB_WIDTH + Offset,
  618.         vw -> sy * VisHeight / SUB_HEIGHT + Offset,
  619.         vw -> window -> Width,
  620.         vw -> window -> Height);
  621.         }
  622.  
  623.     Permit ();
  624.       }
  625.     }
  626.   }
  627. }
  628.  
  629. int
  630. mouse_event (struct IntuiMessage *msg, struct Callback *cb)
  631. {
  632.   static ULONG lsecs = 0, lmicros = 0;
  633.   static int start_x, start_y;
  634.   ULONG secs = 0, micros = 0;
  635.   int x, y;
  636.  
  637.   x = Win -> GZZMouseX;
  638.   y = Win -> GZZMouseY;
  639.  
  640.   switch (msg -> Code)
  641.   {
  642.     case SELECTDOWN:
  643.       CurrentTime (&secs, µs);
  644.       if (DoubleClick (lsecs, lmicros, secs, micros))
  645.       {
  646.     lsecs = lmicros = 0;
  647.     change_area (x, y);
  648.       }
  649.       else
  650.       {
  651.         if (Cvw = find_window (x, y))
  652.         {
  653.           Action = ACT_MOVE_WIN;
  654.           SetDrMd (Rp, COMPLEMENT);
  655.           draw_vwindow (WHITE, Cvw); /* Create temporary image */
  656.       Dx = msg -> MouseX;
  657.        Dy = msg -> MouseY;
  658.  
  659.       start_x = Cvw -> sx;
  660.       start_y = Cvw -> sy;
  661.         }
  662.         lsecs = secs;
  663.         lmicros = micros;
  664.       }
  665.       break;
  666.  
  667.     case SELECTUP:
  668.       if (Cvw)
  669.       {
  670.     int area;
  671.  
  672.     Action = ACT_NONE;
  673.     draw_vwindow (WHITE, Cvw); /* Remove temporary image */
  674.     SetDrMd (Rp, JAM2);
  675.  
  676.     area = vAREA (x, y);
  677.  
  678.     while (Cvw -> sx < 0) Cvw -> sx += SUB_WIDTH;
  679.     while (Cvw -> sy < 0) Cvw -> sy += SUB_HEIGHT;
  680.     Cvw -> sx %= SUB_WIDTH;
  681.     Cvw -> sy %= SUB_HEIGHT;
  682.  
  683.     if ((start_x + 1 > Cvw -> sx && start_x - 1 < Cvw -> sx &&
  684.          start_y + 1 > Cvw -> sy && start_y - 1 < Cvw -> sy &&
  685.          area == Cvw -> area) ||
  686.         (area != Cvw -> area && Cvw -> window == Win))
  687.     {
  688.       Cvw = NULL;
  689.       break;
  690.     }
  691.     
  692.     Forbid ();
  693.  
  694.     if (assert_window (Cvw -> window))
  695.     {
  696.       struct Window *win;
  697.  
  698.       win = Cvw -> window;
  699.  
  700.       if (area == Area)    /* Destination area is visible */
  701.       {
  702.         if (Options & OPT_MOVE_SCREEN) {
  703.           ChangeWindowBox (Cvw -> window,
  704.         Cvw -> sx * VisWidth  / SUB_WIDTH  + AREA_X (area) * VisWidth,
  705.         Cvw -> sy * VisHeight / SUB_HEIGHT + AREA_Y (area) * VisHeight,
  706.         win -> Width, win -> Height);
  707.         }
  708.         else {
  709.           ChangeWindowBox (Cvw -> window,
  710.         Cvw -> sx * VisWidth  / SUB_WIDTH,
  711.         Cvw -> sy * VisHeight / SUB_HEIGHT,
  712.         win -> Width, win -> Height);
  713.         }
  714.       }
  715.       else
  716.       {
  717.         if (Options & OPT_MOVE_SCREEN) {    /* Six areas (3 * 2) */
  718.           ChangeWindowBox (Cvw -> window,
  719.         Cvw -> sx * VisWidth  / SUB_WIDTH  + AREA_X (area) * VisWidth,
  720.         Cvw -> sy * VisHeight / SUB_HEIGHT + AREA_Y (area) * VisHeight,
  721.         win -> Width, win -> Height);
  722.         }
  723.         else {                /* Two `real' areas (1 * 2) */
  724.           ChangeWindowBox (Cvw -> window,
  725.         0, VisHeight, win -> Width, win -> Height);        
  726.         }
  727.       }
  728.       Permit ();
  729.  
  730.       Cvw -> area = area;
  731.     }
  732.     else {
  733.       Permit ();
  734.       DisplayBeep (Win -> WScreen);
  735.     }
  736.     Cvw = NULL;
  737.  
  738.     redraw_graphic ();
  739.       }
  740.       break;
  741.  
  742.  
  743.     case MIDDLEDOWN: break;
  744.     case MIDDLEUP:
  745.       change_area (x, y);
  746.       break;
  747.  
  748.     case MENUDOWN: break;
  749.     case MENUUP:
  750.       if (Cvw) break;
  751.       if (Cvw = find_window (x, y))
  752.       {
  753.         Forbid ();
  754.         if (assert_window (Cvw -> window))
  755.         {
  756.           ZipWindow (Cvw -> window);
  757.     }
  758.         Permit ();
  759.     Cvw = NULL;
  760.       }
  761.       break;
  762.  
  763.     default: break;
  764.   }
  765.   return 0;
  766. }
  767.  
  768.  
  769. /* Shouldn't this disable SAS/C's ctrl-c handling? */
  770. void CXBRK     () {}
  771. void chkabort  () {}
  772.  
  773.